package com.douqu.game.core.factory;

import com.bean.core.buffer.ByteBuffer;
import com.bean.core.util.TimeUtils;
import com.bean.core.util.Utils;
import com.douqu.game.core.config.FunctionConfig;
import com.douqu.game.core.config.StableDataConfig;
import com.douqu.game.core.controller.PlayerController;
import com.douqu.game.core.database.model.ServerModel;
import com.douqu.game.core.e.E_CityInOutType;
import com.douqu.game.core.e.E_StableDataType;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.entity.battle.BattleTemp;
import com.douqu.game.core.entity.world.*;
import com.douqu.game.core.entity.world.map.SpritePlayerBean;
import com.douqu.game.core.entity.world.map.WorldMapData;
import com.douqu.game.core.entity.world.map.WorldMapUpdateResult;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.CoreUtils;
import com.douqu.game.core.util.LogUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author: Bean
 * @Description:
 * @Date: 2018-02-06 17:21
 */
public class WorldInfoFactory {

    private static WorldInfoFactory instance = null;

    private int id;

    private String name;

    private volatile int playerIndex;

    private volatile int goodsIndex;

    /**
     * 认证服务器地址
     */
    private String authServerHost;

    private String configUpdateHost;

    private int freeCount;

    private int crowdCount;

    private int fullCount;

    //TODO 开服红利全服购买人数
    //private int bonusCount;

    public List<String> collectRobotPlayerIndex = new ArrayList<>();

    /**
     * 当前服务器状态
     */
    private SGCommonProto.E_SERVER_STATUS serverStatus;

    private WorldOfficialData worldOfficialData;

    private WorldArenaData worldArenaData;

    private WorldRankData worldRankData;

    private WorldCollectData worldCollectData;

    private WorldBossData worldBossData;

    private WorldAuctionData worldAuctionData;

    private WorldMapData worldMapData;

    private Date startServerTime;

    /**
     * 单人战场的大地图信息
     */
    private Map<String, WorldMapData> playerWorldMapDataMap = new ConcurrentHashMap<>();

    /**
     * 临时存储玩家军队信息
     */
    private Map<String, BattleTemp> playerWorldMapBattleTempCache = new ConcurrentHashMap<>();
//    /**
//     * 需要销毁单人战场数据的玩家
//     */
//    private List<String> destroySingleWorldMapList = new CopyOnWriteArrayList<>();

    private WorldInfoFactory()
    {
        playerIndex = ConstantFactory.INIT_PLAYER_INDEX;
        goodsIndex = ConstantFactory.INIT_GOODS_INDEX;
        serverStatus = SGCommonProto.E_SERVER_STATUS.SERVER_STATUS_FREE;
        name = "";

        worldOfficialData = new WorldOfficialData();
        worldArenaData = new WorldArenaData();
        worldRankData = new WorldRankData();
        worldCollectData = new WorldCollectData();

        worldBossData = new WorldBossData();
        worldAuctionData = new WorldAuctionData();
        worldMapData = new WorldMapData(null);
    }

    public static WorldInfoFactory getInstance()
    {
        if(instance == null)
            instance = new WorldInfoFactory();

        return instance;
    }

    public void loadWorldInfo(byte[] data)
    {
        if(data == null)
            return;

        ByteBuffer buffer = new ByteBuffer(data);
        worldOfficialData.loadFrom(buffer);
        worldArenaData.loadFrom(buffer);
        worldRankData.loadFrom(buffer);
        worldCollectData.loadFrom(buffer);
        worldBossData.loadFrom(buffer);
        worldAuctionData.loadFrom(buffer);
        worldMapData.loadFrom(buffer);

        buffer.readBoolean();
    }

    public void loadPlayerMapInfo(byte[] data)
    {
        if(data == null)
            return;

        ByteBuffer singleBuffer = new ByteBuffer(data);
        int size = singleBuffer.readInt();
        WorldMapData singleWorldMap = null;
        String playerIndex = "";
        for(int i = 0; i < size; i++)
        {
            playerIndex = singleBuffer.readUTF();

            singleWorldMap = new WorldMapData(playerIndex);

            playerWorldMapDataMap.put(playerIndex, singleWorldMap);

            singleWorldMap.loadFrom(singleBuffer);
        }
    }

    public void load(ServerModel serverModel)
    {
        if(serverModel == null)
            return;

        id = serverModel.getId();
        name = serverModel.getName();
        playerIndex = serverModel.getPlayerIndex() + 1;
        goodsIndex = serverModel.getGoodsIndex() + 1;
        authServerHost = serverModel.getAuthServerHost();
        startServerTime = serverModel.getCreateTime() == null ? new Date() : serverModel.getCreateTime();
        freeCount = serverModel.getFreeCount();
        crowdCount = serverModel.getCrowdCount();
        fullCount = serverModel.getFullCount();
        //bonusCount = serverModel.getBonusCount();

        if(serverModel.getWorldInfo() == null)
        {
            worldOfficialData.init();
            worldArenaData.init();
            worldRankData.init();
            worldCollectData.init();
	        worldBossData.init();
			worldAuctionData.init();
            worldMapData.init();
        }
        else
        {
            loadWorldInfo(serverModel.getWorldInfo());

            worldOfficialData.checkInit();
            worldArenaData.checkInit();
            worldRankData.checkInit();
            worldCollectData.checkInit();
            worldBossData.checkInit();
            worldAuctionData.checkInit();
            worldMapData.checkInit();

            worldOfficialData.checkReset();
            worldArenaData.checkReset();
            worldRankData.checkReset();
            worldCollectData.checkReset();
            worldBossData.checkReset();
            worldAuctionData.checkReset();
            worldMapData.checkReset();
        }

        //每次都重新刷驻军
        LogUtils.debug("大地图开始初始化驻军--------------------->");
        worldMapData.initGarrison();
        LogUtils.debug("大地图初始化驻军完成--------------------->");

        //从数据库读取新的单人战场数据
        loadPlayerMapInfo(serverModel.getPlayerWorldMapInfo());

        LogUtils.info("serverModel -> " + serverModel);
    }

    public byte[] saveWorldInfo()
    {
        ByteBuffer buffer = new ByteBuffer();
        worldOfficialData.writeTo(buffer);
        worldArenaData.writeTo(buffer);
        worldRankData.writeTo(buffer);
        worldCollectData.writeTo(buffer);
        worldBossData.writeTo(buffer);
        worldAuctionData.writeTo(buffer);

        worldMapData.writeTo(buffer);

        buffer.writeBoolean(false);

        return buffer.getBytes();
    }

    public byte[] savePlayerWorldMapInfo()
    {
        ByteBuffer singleBuffer = new ByteBuffer();
        singleBuffer.writeInt(playerWorldMapDataMap.size());
        for(Map.Entry<String, WorldMapData> entry : playerWorldMapDataMap.entrySet())
        {
            singleBuffer.writeUTF(entry.getKey());

            entry.getValue().writeTo(singleBuffer);
        }
        return singleBuffer.getBytes();
    }


    public ServerModel save()
    {
        if(id == 0)
            return null;

        ServerModel serverModel = new ServerModel();
        serverModel.setId(id);
        serverModel.setName(name);
        serverModel.setPlayerIndex(playerIndex);
        serverModel.setGoodsIndex(goodsIndex);
        serverModel.setAuthServerHost(authServerHost);
        serverModel.setFreeCount(freeCount);
        serverModel.setCrowdCount(crowdCount);
        serverModel.setFullCount(fullCount);
        //serverModel.setBonusCount(bonusCount);
        serverModel.setCreateTime(startServerTime);

        serverModel.setWorldInfo(saveWorldInfo());

        serverModel.setPlayerWorldMapInfo(savePlayerWorldMapInfo());

        return serverModel;
    }

    public WorldMapUpdateResult update(long currentTime)
    {
        WorldMapUpdateResult updateResult = new WorldMapUpdateResult();

        worldMapData.update(currentTime, updateResult);

        for(WorldMapData singleWorldMapData : playerWorldMapDataMap.values())
        {
            singleWorldMapData.update(currentTime, updateResult);
        }

        return updateResult;
    }

//    public void setPlayerAverageLv(int lv)
//    {
//        worldMapData.setPlayerAverageLevel(lv);
//
//        for(WorldMapData singleWorldMapData : playerWorldMapDataMap.values())
//        {
//            singleWorldMapData.setPlayerAverageLevel(lv);
//        }
//    }

    /**
     * 更新服务器状态
     * @param playerCount
     * @return true表示有改变
     */
    public boolean updateServerStatus(int playerCount)
    {
        int beforeStatus = serverStatus.getNumber();

        if(playerCount >= fullCount)
            serverStatus = SGCommonProto.E_SERVER_STATUS.SERVER_STATUS_FULL;
        else if(playerCount >= crowdCount)
            serverStatus = SGCommonProto.E_SERVER_STATUS.SERVER_STATUS_CROWD;
        else if(playerCount >= freeCount)
            serverStatus = SGCommonProto.E_SERVER_STATUS.SERVER_STATUS_FREE;

        return beforeStatus != serverStatus.getNumber();
    }


    public void removePlayer(Player player)
    {
        worldArenaData.removePlayer(player);
        worldOfficialData.removePlayer(player);
        worldRankData.removePlayer(player);
    }

    public void removePlayerWorldMap(String playerIndex)
    {
        playerWorldMapDataMap.remove(playerIndex);
    }

    public WorldMapData addPlayerWorldMap(Player player)
    {
        WorldMapData singleWorldMap = playerWorldMapDataMap.get(player.getObjectIndex());
        if(singleWorldMap != null)
            return singleWorldMap;

        singleWorldMap = new WorldMapData(player.getObjectIndex());
        singleWorldMap.setPlayerAverageLevel(player.getLv());

        playerWorldMapDataMap.put(player.getObjectIndex(), singleWorldMap);

        //第1步:初始化所有城
        singleWorldMap.init();
        //第2步:给城设置主人
//        singleWorldMap.updateMasterPlayerIndex(player.getObjectIndex());
        //第3步:初始驻军
        singleWorldMap.initGarrison();

        LogUtils.debug("单人战场初始化 -> " + player.getName());

        return singleWorldMap;
    }

    public WorldMapData getPlayerWorldMap(String playerIndex)
    {
        return playerWorldMapDataMap.get(playerIndex);
    }

//    public void addDestroySingleWorldMap(String playerIndex)
//    {
//        if(destroySingleWorldMapList.contains(playerIndex))
//            return;
//
//        destroySingleWorldMapList.add(playerIndex);
//    }
//
//    public boolean isDestroySingleWorldMap(String playerIndex)
//    {
//        return destroySingleWorldMapList.contains(playerIndex);
//    }
//
//    public void removeDestroySingleWorldMap(String playerIndex)
//    {
//        destroySingleWorldMapList.remove(playerIndex);
//    }

    public BattleTemp getCacheBattleTemp(String playerIndex)
    {
        return playerWorldMapBattleTempCache.get(playerIndex);
    }

    public void removeCacheBattleTemp(String playerIndex)
    {
        playerWorldMapBattleTempCache.remove(playerIndex);
    }

    /**
     * 获取新的玩家流水号
     * @return
     */
    public String createPlayerIndex()
    {
        return id + "" + (++playerIndex) + CoreUtils.createUUID(6).toUpperCase();
    }

    /**
     * 创建新的物品流水号
     * @return
     */
    public String createGoodsIndex()
    {
        return (++goodsIndex) + CoreUtils.createUUID(4).toUpperCase();
    }

    public int getServerId()
    {
        return id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public SGCommonProto.E_SERVER_STATUS getServerStatus() {
        return serverStatus;
    }

    public void setServerStatus(SGCommonProto.E_SERVER_STATUS serverStatus) {
        this.serverStatus = serverStatus;
    }

    public int getPlayerIndex() {
        return playerIndex;
    }

    public void setPlayerIndex(int playerIndex) {
        this.playerIndex = playerIndex;
    }

    public int getGoodsIndex() {
        return goodsIndex;
    }

    public void setGoodsIndex(int goodsIndex) {
        this.goodsIndex = goodsIndex;
    }

    public WorldArenaData getArenaRankInfo() {
        return worldArenaData;
    }

    public Date getStartServerTime() {
        return startServerTime;
    }

    public void setStartServerTime(Date startServerTime) {
        this.startServerTime = startServerTime;
    }

    public String getAuthServerHost() {
        return authServerHost;
    }

    public void setAuthServerHost(String authServerHost) {
        this.authServerHost = authServerHost;
    }

    public int getFreeCount() {
        return freeCount;
    }

    public void setFreeCount(int freeCount) {
        this.freeCount = freeCount;
    }

    public int getCrowdCount() {
        return crowdCount;
    }

    public void setCrowdCount(int crowdCount) {
        this.crowdCount = crowdCount;
    }

    public int getFullCount() {
        return fullCount;
    }

    public void setFullCount(int fullCount) {
        this.fullCount = fullCount;
    }

    public String getConfigUpdateHost() {
        return configUpdateHost;
    }

    public void setConfigUpdateHost(String configUpdateHost) {
        this.configUpdateHost = configUpdateHost;
    }

    public WorldOfficialData getWorldOfficialData() {
        return worldOfficialData;
    }

    public WorldArenaData getWorldArenaData() {
        return worldArenaData;
    }

    public WorldRankData getWorldRankData() {
        return worldRankData;
    }


    public void setId(int id) {
        this.id = id;
    }


    public WorldCollectData getWorldCollectData() {
        return worldCollectData;
    }

	public WorldBossData getWorldBossData() {
        return worldBossData;
    }

	public WorldAuctionData getWorldAuctionData() {
        return worldAuctionData;
    }

//    public int getBonusCount() {
//        return bonusCount;
//    }
//
//    public void setBonusCount(int bonusCount) {
//        this.bonusCount = bonusCount;
//    }

    public WorldMapData getWorldMapData(String... playerIndex)
    {
        if(playerIndex.length == 0 || Utils.isNullOrEmpty(playerIndex[0]))
            return worldMapData;
        else
            return playerWorldMapDataMap.get(playerIndex[0]);
    }

    public WorldMapData getWorldMapData(PlayerController playerController)
    {
        FunctionConfig functionConfig = DataFactory.getInstance().getGameObject(DataFactory.FUNCTION_KEY, FunctionFactory.INTO_WORLD_MAP);
        if(playerController.getPlayer().getLv() < functionConfig.lv)
            return null;

        //1.是否已经在大地图里 2.是否处于单人战场
        boolean isSingleByLv = isSingleWorldMapByLv(playerController.getPlayer());
        boolean isSingle = false;
        if(playerController.isInWorldMap())
        {
            //获取单人战场数据
            isSingle = playerController.isSingleWorldMap() || isSingleByLv;
        }
        else
        {
            //没有处于大地图里,检测等级就行
            isSingle = isSingleByLv;
        }

        if(isSingle)
        {
            WorldMapData singleWorldMap = playerWorldMapDataMap.get(playerController.getObjectIndex());
            if(singleWorldMap == null)
            {
                singleWorldMap = addPlayerWorldMap(playerController.getPlayer());
            }
            playerController.setSingleWorldMap(true);
            return singleWorldMap;
        }
        else
        {
            playerController.setSingleWorldMap(false);
            playerController.getPlayer().getWorldMapTaskData().setSingleMapEnd(true);
            return worldMapData;
        }
    }

    public SpritePlayerBean removeSingleWorldMap(String playerIndex)
    {
        WorldMapData singleWorldMap = playerWorldMapDataMap.get(playerIndex);
        if(singleWorldMap != null)
        {
            SpritePlayerBean spritePlayerBean = singleWorldMap.getPlayerActionBean(playerIndex);
            if(spritePlayerBean != null)
                playerWorldMapBattleTempCache.put(spritePlayerBean.getObjectIndex(), spritePlayerBean.getBattleTemp());
//            if(spritePlayerBean != null)
//            {
//                if(spritePlayerBean.isBattle())
//                {
//                    LogUtils.debug("删除单人战场数据，但是玩家现在在战斗中，先缓存，等会再删 -> " + playerController.getName());
//                    //在战斗结束时要检测是否是要销毁的
//                }
//                else
//                {
//                    LogUtils.debug("删除单人战场数据 -> " + playerController.getName());
//                    removePlayerWorldMap(playerController.getObjectIndex());
//                }
//            }
//            else
//            {
                LogUtils.debug("删除单人战场数据 -> " + playerIndex);
                removePlayerWorldMap(playerIndex);
//            }

            return spritePlayerBean;
        }

        return null;
    }

    public boolean isSingleWorldMapByLv(Player player)
    {
        StableDataConfig stableDataConfig = DataFactory.getInstance().getGameObject(DataFactory.STABLE_DATA_KEY, E_StableDataType.WORLD_MAP.getCode());
        if(player.getLv() < stableDataConfig.intValue && !player.getWorldMapTaskData().isSingleMapEnd())
        {
            return true;
        }

        return false;
    }


    public Map<String, WorldMapData> getPlayerWorldMapDataMap()
    {
        return playerWorldMapDataMap;
    }


    /**
     * 大地图进出城记录(临时用)
     */
    private List<InOutCityRecord> inOutCityRecordList = new CopyOnWriteArrayList<>();

    public void addInOutCityRecord(String cityName, String playerName, E_CityInOutType type, boolean isSingleWorldMap)
    {
        InOutCityRecord record = new InOutCityRecord();
        record.setCreateTime(DataFactory.currentTime);
        record.setCityName(cityName);
        record.setPlayerName(playerName);
        record.setType(type);
        record.setRemark((isSingleWorldMap ? "单人战场->" : "世界地图->") + type.getMsg());

        inOutCityRecordList.add(record);
    }

    public void clearInOutCityRecord()
    {
        inOutCityRecordList.clear();
    }

    public List<InOutCityRecord> getInOutCityRecordList() {
        return inOutCityRecordList;
    }

    public class InOutCityRecord
    {
        private long createTime;

        private String cityName;

        private String playerName;

        private String remark;

        private E_CityInOutType type;

        public E_CityInOutType getType() {
            return type;
        }

        public void setType(E_CityInOutType type) {
            this.type = type;
        }

        public String getCreateTime() {
            return TimeUtils.getFormatTime(createTime);
        }

        public void setCreateTime(long createTime) {
            this.createTime = createTime;
        }

        public String getCityName() {
            return cityName;
        }

        public void setCityName(String cityName) {
            this.cityName = cityName;
        }

        public String getPlayerName() {
            return playerName;
        }

        public void setPlayerName(String playerName) {
            this.playerName = playerName;
        }

        public String getRemark() {
            return remark;
        }

        public void setRemark(String remark) {
            this.remark = remark;
        }
    }
}
